
import OauthServer, { Request, Response } from 'oauth2-server';
import * as model from './model'
export default class OAuthServer {
    constructor(options) {
        options = options || { model };
        this.server = new OauthServer(options);
    }
    /**
     * Authentication Middleware.
     *
     *  a middleware that will validate a token.
     *
     * (See: https://tools.ietf.org/html/rfc6749#section-7)
     */
    authenticate() {
        return async (ctx, next) => {
            let server = this.server;
            let request = new Request(ctx.request);
            let response = new Response(ctx.response);
            let token
            try {
                token = await this.server.authenticate(request, response)
            } catch (e) {
                return this._handleError(ctx, e);
            }
            ctx.state.oauth = { token };
            await next();
        }
    }

    /**
     * Authorization Middleware.
     *
     *  a middleware that will authorize a client to request tokens.
     *
     * (See: https://tools.ietf.org/html/rfc6749#section-3.1)
     */
    authorize() {
        return async (ctx, next) => {

            let server = this.server;
            let request = new Request(ctx.request);
            let response = new Response(ctx.response);
            let code
            try {
                code = await server.authorize(request, response)
            } catch (e) {
                return this._handleError(ctx, e, response);
            }
            ctx.state.oauth = { code };
            this._handleResponse(ctx, response);

            await next();
        }
    }


    /**
     * Grant Middleware
     *
     *  middleware that will grant tokens to valid requests.
     *
     * (See: https://tools.ietf.org/html/rfc6749#section-3.2)
     */
    token() {
        return async (ctx, next) => {
            let server = this.server;
            let request = new Request(ctx.request);
            let response = new Response(ctx.response);
            let token
            try {
                token = await server.token(request, response)
            } catch (e) {
                return this._handleError(ctx, e, response);
            }
            ctx.state.oauth = { token };
            this._handleResponse(ctx, response);
            await next();
        }
    };


    /**
     * Handle response.
     */

    _handleResponse(ctx, response) {
        ctx.body = response.body;
        ctx.status = response.status;
        ctx.set(response.headers);
    }
    /**
     * Handle error.
     */
    _handleError(ctx, e, response) {
        if (response) {
            ctx.set(response.headers);
        }
        const env = process.env.NODE_ENV || 'development'
        ctx.body = { error: e.name, error_description: e.message };
        ctx.throw(e)
    }

}


